package es.unileon.rnag.jgen;
import java.util.*;
import es.unileon.rnag.jgen.operadores.*;

/**
 * Clase que representa la estrategia a seguir por el algoritmo gen&eacute;tico
 * @author Abel Mayorga Gonz&aacute;lez
 * @author Sergio Fern&aacute;ndez Mart&iacute;nez
 * @version 1.0
 */
public class Estrategia {
	/**
	 * Estrategia predefinida: Selecci&oacute;n por torneo y Crossover con un punto de corte
	 */
	public static final int TORNEO_UN_PUNTO = 0;
	/**
	 * Estrategia predefinida: Selecci&oacute;n por torneo y Crossover con dos puntos de corte
	 */
	public static final int TORNEO_DOS_PUNTOS = 1;
	/**
	 * Estrategia predefinida: Selecci&oacute;n por torneo y Crossover uniforme
	 */
	public static final int TORNEO_UNIFORME = 2;
	/**
	 * Estrategia predefinida: Selecci&oacute;n por ruleta y Crossover con un punto de corte
	 */
	public static final int RULETA_UN_PUNTO = 3;
	/**
	 * Estrategia predefinida: Selecci&oacute;n por ruleta y Crossover con dos puntos de corte
	 */
	public static final int RULETA_DOS_PUNTOS = 4;
	/**
	 * Estrategia predefinida: Selecci&oacute;n por ruleta y Crossover uniforme
	 */
	public static final int RULETA_UNIFORME = 5;
	/**
	 * Estrategia predefinida: Selecci&oacute;n aleatoria y Crossover con un punto de corte
	 */
	public static final int ALEATORIO_UN_PUNTO = 6;
	/**
	 * Estrategia predefinida: Selecci&oacute;n aleatoria y Crossover con dos puntos de corte
	 */
	public static final int ALEATORIO_DOS_PUNTOS = 7;
	/**
	 * Estrategia predefinida: Selecci&oacute;n aleatoria y Crossover uniforme
	 */
	public static final int ALEATORIO_UNIFORME = 8;
	
	private Operador _op[];
	
	/**
	 * Constructor de estrategias predefinidas
	 * @param predefinida: Opci&oacute;n de estrategia predefinida
	 * @param probCross: Probabilidad de crossover en tanto por uno
	 * @param probMuta: Probabilidad de mutaci&oacute;n en tanto por uno
	 */
	public Estrategia (int predefinida, float probCross, float probMuta){
		Seleccion s = null;
		Crossover c = null;
		Mutacion m = new MutacionBasica (probMuta);
		switch (predefinida){
		case TORNEO_UN_PUNTO:
		case TORNEO_DOS_PUNTOS:
		case TORNEO_UNIFORME:
			s = new SeleccionTorneo(1);
			break;
		case RULETA_UN_PUNTO:
		case RULETA_DOS_PUNTOS:
		case RULETA_UNIFORME:
			s = new SeleccionRuleta(1);
		case ALEATORIO_UN_PUNTO:
		case ALEATORIO_DOS_PUNTOS:
		case ALEATORIO_UNIFORME:
			s = new SeleccionAleatoria(1);
		}
		switch (predefinida){
		case TORNEO_UN_PUNTO:
		case RULETA_UN_PUNTO:
		case ALEATORIO_UN_PUNTO:
			c = new CrossoverUnPunto(probCross);
			break;
		case TORNEO_DOS_PUNTOS:
		case RULETA_DOS_PUNTOS:
		case ALEATORIO_DOS_PUNTOS:
			c = new CrossoverDosPuntos(probCross);
			break;
		case TORNEO_UNIFORME:
		case RULETA_UNIFORME:
		case ALEATORIO_UNIFORME:
			c = new CrossoverUniforme(probCross, 0.5f);
			break;
		}
		_op = new Operador [3];
		_op[0] = s;
		_op[1] = c;
		_op[2] = m;
		
	}
	
	/**
	 * Constructor de estrategias personalizadas
	 * @param op: Array con los operadores a aplicar
	 */
	public Estrategia (Operador op[]){
		_op = op;
	}
	
	/**
	 * Obtiene la siguiente generaci&oacute;n
	 * @param poblacion: Poblaci&oacute;n inicial de la generaci&oacute;n
	 * @param generacion: N&uacute;mero de la generaci&oacute;n
	 * @return La poblaci&oacute;n final de la generaci&oacute;n
	 */
	public List<Cromosoma> siguientePoblacion (List<Cromosoma> poblacion, int generacion){
		List<Cromosoma> siguientePoblacion = new ArrayList<Cromosoma>();
		List<Cromosoma> poblacionSiguienteOp = poblacion;
		//Se pasa la poblacion a traves de los operadores
		for (int i=0; i<_op.length; i++){
			poblacionSiguienteOp = _op[i].operar(generacion, poblacionSiguienteOp);
		}
		//Se obtienen los posibles seleccionados para la siguiente generacion de cada operador
		for (int i=0; i<_op.length; i++){
			siguientePoblacion.addAll(_op[i].getSiguienteGeneracion());
		}
		//Se combinan las dos listas y se devuelve
		siguientePoblacion.addAll(poblacionSiguienteOp);
		return siguientePoblacion;
	}

}
